﻿using ShopPowerTemplate.Commands;
using ShopPowerTemplate.Common;
using ShopPowerTemplate.Common.Authentication;
using ShopPowerTemplate.Entities;
using ShopPowerTemplate.WebServiceReference;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.Storage;
using Windows.UI.Popups;

namespace ShopPowerTemplate.ViewModels
{
    public class ShoppingCartViewModel : BindableBase
    {
        private string _title = "Cesta";
        public string Title
        {
            get { return _title; }
            set { this.SetProperty(ref this._title, value); }
        }

        ObservableCollection<CartItem> _cartList = new ObservableCollection<CartItem>();
        public ObservableCollection<CartItem> CartList
        {
            get { return this._cartList; }
            set
            {
                this.SetProperty(ref this._cartList, value);
            }
        }

        decimal itemsTotal = 0;
        public decimal ItemsTotal
        {
            get { return this.itemsTotal; }
            set
            {
                this.SetProperty(ref this.itemsTotal, value);
            }
        }

        Decimal shippingCost = 0;
        public Decimal ShippingCost
        {
            get { return this.shippingCost; }
            set
            {
                this.SetProperty(ref this.shippingCost, value);
            }
        }

        Decimal discount = 0;
        public Decimal Discount
        {
            get { return this.discount; }
            set
            {
                this.SetProperty(ref this.discount, value);
            }
        }

        Decimal taxes = 0;
        public Decimal Taxes
        {
            get { return this.taxes; }
            set
            {
                this.SetProperty(ref this.taxes, value);
            }
        }

        decimal total = 0;
        public decimal Total
        {
            get { return this.total; }
            set
            {
                this.SetProperty(ref this.total, value);
            }
        }

        decimal itemsCount = 0;
        public decimal ItemsCount
        {
            get { return this.itemsCount; }
            set
            {
                this.SetProperty(ref this.itemsCount, value);
            }
        }

        bool hasItems = false;
        public bool HasItems
        {
            get { return this.hasItems; }
            set
            {
                this.SetProperty(ref this.hasItems, value);
            }
        }

        public ShoppingCartViewModel()
        {
            DefineCommands();
            LoadData();
            this.PropertyChanged += ShoppingCart_Changed;
            this.CartList.CollectionChanged += CartList_CollectionChanged;
            App.Current.Suspending += App_Suspending;
        }

        void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
        {
            SaveData();
        }

        void ShoppingCart_Changed(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Refresh();
        }

        void CartList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (CartItem cartItem in e.NewItems)
                    cartItem.PropertyChanged += ShoppingCart_Changed;
            }

            Refresh();
        }

        private async void AddProduct(ProductPresenterDetailViewModel productPresenter)
        {
            WebServiceClient service = new WebServiceClient();
            ObservableCollection<Option> options = new ObservableCollection<Option>(productPresenter.ProductOptions.Select(p => p.SelectedOption));
            ProductDetail productDetail = await service.GetProductDetailAsync(productPresenter.Product, options);
            
            CartItem cartItem = CartList.FirstOrDefault(x => x.ProductDetail.Id == productDetail.Id);
            if (cartItem != null)
                cartItem.ItemsCount++;
            else
                CartList.Add(new CartItem(productPresenter, productDetail, 1));
        }

        private void RemoveProduct(CartItem cartItem)
        {
            if (cartItem != null)
                CartList.Remove(cartItem);
        }

        private async void Refresh()
        {
            this.PropertyChanged -= ShoppingCart_Changed;

            WebServiceClient service = new WebServiceClient();
            decimal totalWeight = CartList.Sum(item => item.ProductPresenter.Product == null ? 0 : item.ProductPresenter.Product.Weight) ?? 0;

            ItemsTotal = CartList.Sum(item => ((item.ProductPresenter.Product == null ? 0 : item.ProductPresenter.Product.Price) * (decimal)item.ItemsCount));
            Discount = CartList.Sum(item => item.ProductPresenter.Product == null ? 0 : (item.ProductPresenter.Product.Price * (-Math.Abs(item.ProductPresenter.Product.Discount ?? 0 / 100)) * (decimal)item.ItemsCount));
            Taxes = CartList.Sum(item => item.ProductPresenter.Product == null ? 0 : (item.ProductPresenter.Product.Price * (1 - (item.ProductPresenter.Product.Discount ?? 0 / 100)) * (item.ProductPresenter.Product.Tax / 100) * (decimal)item.ItemsCount));
            ShippingCost = await service.GetShippingCostAsync(totalWeight);
            Total = ItemsTotal + Discount + Taxes + ShippingCost;
            ItemsCount = CartList.Sum(item => item.ItemsCount);
            HasItems = CartList.Count > 0;

            this.PropertyChanged += ShoppingCart_Changed;
        }

        private async void LoadData()
        {
            this.PropertyChanged -= ShoppingCart_Changed;

            ApplicationDataContainer container = ApplicationData.Current.RoamingSettings;

            if (container.Values.ContainsKey("Products"))
                await LoadCartList(CartList, ApplicationData.Current.RoamingSettings.Values["Products"].ToString());

            this.PropertyChanged += ShoppingCart_Changed;
        }

        private async Task LoadCartList(ObservableCollection<CartItem> cartList, string data)
        {
            if (!string.IsNullOrWhiteSpace(data))
            {
                cartList.Clear();
                var storedCartList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CartItemSerializable>>(data);
                WebServiceClient service = new WebServiceClient();

                foreach (var item in storedCartList)
                {
                    var productDetail = await service.FindProductDetailAsync(item.ProductDetailId);
                    var product = await service.FindProductAsync(productDetail.Product.Id);
                    productDetail.Product = product;

                    ProductPresenterDetailViewModel model = new ProductPresenterDetailViewModel(product);
                    CartItem cartItem = new CartItem(model, productDetail, item.ItemsCount);
                    cartList.Add(cartItem);
                }
            }
        }

        private void SaveData()
        {
            ApplicationDataContainer container = ApplicationData.Current.RoamingSettings;

            string carList = Newtonsoft.Json.JsonConvert.SerializeObject(CartList.Select(c => new CartItemSerializable { ItemsCount = c.ItemsCount, ProductId = c.ProductPresenter.Product.Id, ProductDetailId = c.ProductDetail.Id }).ToList());

            if (!container.Values.ContainsKey("Products"))
                ApplicationData.Current.RoamingSettings.Values.Add("Products", carList);
            else
                ApplicationData.Current.RoamingSettings.Values["Products"] = carList;
        }

        #region Commands

        private ICommand _AddProductCommand;
        public ICommand AddProductCommand
        {
            get
            {
                return _AddProductCommand;
            }
        }

        private ICommand _RemoveProductCommand;
        public ICommand RemoveProductCommand
        {
            get
            {
                return _RemoveProductCommand;
            }
        }

        private void DefineCommands()
        {
            _AddProductCommand = new AddProductCommand(OnAddProductCommand, OnCanExecuteAddProductCommand);
            _RemoveProductCommand = new RemoveProductCommand(OnRemoveProductCommand);
        }

        private void OnAddProductCommand(ProductPresenterDetailViewModel productPresenter)
        {
            AddProduct(productPresenter);
        }

        private bool OnCanExecuteAddProductCommand(ProductPresenterDetailViewModel productPresenter)
        {
            if (productPresenter == null)
                return false;

            WebServiceClient service = new WebServiceClient();
            Task<bool> t = service.StockAvailableAsync(productPresenter.Product, new ObservableCollection<Option>(productPresenter.ProductOptions.Select(p => p.SelectedOption)));
            t.Wait();
            return t.Result;
        }

        private void OnRemoveProductCommand(CartItem cartItem)
        {
            RemoveProduct(cartItem);
        }

        #endregion Commands

        public bool Validate()
        {
            return CartList.Count > 0 &&
                App.CurrentCustomer.Addresses.Any(a => !a.IsBilling) &&
                App.CurrentCustomer.Addresses.Any(a => a.IsBilling);
        }

        internal void Clear()
        {
            CartList.Clear();
            SaveData();
        }
    }

    public class CartItem : BindableBase
    {
        public ICommand RemoveProductCommand
        {
            get
            {
                return App.ShoppingCart.RemoveProductCommand;
            }
        }

        ProductPresenterDetailViewModel productPresenter = null;
        public ProductPresenterDetailViewModel ProductPresenter
        {
            get { return this.productPresenter; }
            set
            {
                if (this.SetProperty(ref this.productPresenter, value))
                {
                    if (value != null)
                    {
                        value.PropertyChanged +=
                            (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
                            {
                                this.OnPropertyChanged("ProductPresenter");
                            };
                    }
                }
            }
        }

        ProductDetail productDetail = null;
        public ProductDetail ProductDetail
        {
            get { return this.productDetail; }
            set
            {
                this.SetProperty(ref this.productDetail, value);
            }
        }

        int itemsCount = 0;
        private int p;
        public int ItemsCount
        {
            get { return this.itemsCount; }
            set
            {
                this.SetProperty(ref this.itemsCount, value);
            }
        }

        public CartItem()
        {

        }

        public CartItem(ProductPresenterDetailViewModel productPresenter, Entities.ProductDetail productDetail, int itemsCount)
        {
            // TODO: Complete member initialization
            this.productPresenter = productPresenter;
            this.productDetail = productDetail;
            this.itemsCount = itemsCount;
        }
    }

    public class CartItemSerializable
    {
        public int ItemsCount { get; set; }
        public int ProductId { get; set; }
        public int ProductDetailId { get; set; }
    }
}
